#include "MEnviroment.h"

#include <sstream>
#include <vector>
#include <iomanip>

#include "Markup.h"
#include "MException.h"
BEGIN_MARIONETTE
using namespace std;
//////////////////////////////////////////////////////////////////////////

MEnviroment::MEnviroment()
{
	Reset();
}
void MEnviroment::Reset()
{
	MTypes_Imp::ClearAll();
	m_MValuesContainer.clear();
	CreateInnerTypes();
}

Marionette::MValue MEnviroment::NewValue( MString typeName,MAddress addr )
{
	return GetTypeByName(typeName)->CreateValue(addr);
}

void MEnviroment::ImportFrom( MString xml )
{
	CMarkup XmlPaser;
	XmlPaser.SetDoc(xml);
	XmlPaser.ResetPos();
	MString subxml=xml;
	if(XmlPaser.FindElem("Marionette") )
	{
		XmlPaser.IntoElem();
	}

	if(XmlPaser.FindElem("types") )
	{
		MTypes_Imp::ImportFrom(XmlPaser.GetSubDoc());
	} 
	if(XmlPaser.FindElem("values") )
	{
		ImportValueFrom(XmlPaser.GetSubDoc());
	} 
}

void MEnviroment::ExportTo( MString& xml )
{
	xml	="<Marionette>\r\n"+ ExportTypes() + ExportValues()+ "</Marionette>\r\n";
}

void MEnviroment::ImportValueFrom( MString xml )
{
	CMarkup XmlPaser;
	XmlPaser.SetDoc(xml);
	XmlPaser.ResetPos();
	if(XmlPaser.FindElem("values") == false)
		return;
	XmlPaser.IntoElem();
	while(XmlPaser.FindElem("MValue") == true)
	{
		MString valueName = XmlPaser.GetAttrib("name");
		MString typeName = XmlPaser.GetAttrib("type");
		MString addressStr = XmlPaser.GetAttrib("address");
		MString moduleName = XmlPaser.GetAttrib("module");
		stringstream ss(addressStr);
		DWORD address;
		ss>>hex>>address;

		CreateValue(typeName,valueName,MAddress(moduleName, address));
	}
	return;
}

Marionette::MValue MEnviroment::CreateValue( MString typeName,MString valueName,MAddress addr )
{
	MValue v=NewValue(typeName,addr);
	m_MValuesContainer.insert(make_pair(valueName,v));
	return v;
}
void split(std::string src, std::string token, vector<std::string>& vect)   
{   
	int nend=0;   
	int nbegin=0;   
	while(nend != -1)   
	{   
		nend = src.find_first_of(token, nbegin);   
		if(nend == -1)   
			vect.push_back(src.substr(nbegin, src.length()-nbegin));   
		else  
			vect.push_back(src.substr(nbegin, nend-nbegin));   
		nbegin = nend + 1;   
	}   
}  
Marionette::MValue MEnviroment::GetValueByName( MString valueName )
{
	vector<std::string> vect;
	split(valueName,".",vect);

	if(vect.size() == 0 || ValueExist(vect[0]) == false)
		throw MemberNotExist("MEnviroment",vect[0]);

	MValue v=m_MValuesContainer.find(vect[0])->second;
	for(size_t i=1;i<vect.size();i++)
		v = v[vect[i]];
	return v;
}

void MEnviroment::CreateInnerTypes()
{
	MTypes_Imp::CreateInnerTypes();
}

Marionette::MString MEnviroment::ExportValues()
{
	CMarkup xmlBuilder;

	xmlBuilder.AddElem("values");

	MValueContainer_Type::iterator iter;
	for(iter = m_MValuesContainer.begin();iter != m_MValuesContainer.end();iter++)
	{
		xmlBuilder.AddChildElem("MValue");
		xmlBuilder.AddChildAttrib("name",iter->first);
		xmlBuilder.AddChildAttrib("type",iter->second.Type()->Name());
		if (iter->second.ModuleName() != "")
		{
			xmlBuilder.AddChildAttrib("module",iter->second.ModuleName());
		}
		stringstream ss;
		ss<<"0x"<<hex<< std::setw(8) <<std::setfill('0')<<	iter->second.Offset();
		xmlBuilder.AddChildAttrib("address",ss.str());

	}
	return xmlBuilder.GetDoc();
}

Marionette::MString MEnviroment::ExportTypes()
{
	CMarkup xmlBuilder;

	xmlBuilder.AddElem("types");
	xmlBuilder.IntoElem();
	TypeContainer_Type::iterator iter;
	for(iter = m_TypesContainer.begin();iter != m_TypesContainer.end();iter++)
	{
		if(iter->second->NeedSerilize() == true)
		{
			xmlBuilder.AddSubDoc(iter->second->ToXML());
		}
	}
	return xmlBuilder.GetDoc();
}

bool MEnviroment::ValueExist( MString valueName )
{
	MValueContainer_Type::iterator iter = m_MValuesContainer.find(valueName);
	if(iter == m_MValuesContainer.end())
		return false;
	return true;
}

MStruct* MEnviroment::NewStruct( MString structName )
{
	MType* retType = GetTypeByName(structName);
	if (retType == NULL)
	{
		MStruct* pStruct = new MStruct(structName,this);
		AddType(pStruct);
		return pStruct;
	}
	else
	{
		throw TypeNameAlreadyExist();
	}
}
MList* MEnviroment::NewList(MString listName)
{
	MList* pList = new MList(listName,this);
	AddType(pList);
	return pList;
}
MType* MEnviroment::GetTypeByName( MString name )
{
	return MTypes_Imp::GetTypeByName(name);
}

MStruct* MEnviroment::CreateStruct( MString StructName )
{
	 	MType* retType = GetTypeByName(StructName);
	 	if (retType == NULL)
	 	{
	 		MStruct* pStruct = new MStruct(StructName,this);
	 		AddType(pStruct);
	 		return pStruct;
	 	}
	 	else
	 	{
	 		throw TypeNameAlreadyExist();
	 	}
}

MType* MEnviroment::CreateList( MString name )
{
	MList* pListType = new MList(name,this);
	AddType(pListType);
	return pListType;
}




END_MARIONETTE